<?php
/**
 * Ganglib
 *
 * LICENSE
 *
 * This source file is subject to the GNU Lesser Generak Public license.
 * 
 * It is available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/lgpl.html
 *
 * @category    Ganglib
 * @package    Div_Db_Distributor_Strategy_PDO
 * @copyright  Copyright (c) 2008 Ganglib project members (http://www.code.google.com/p/ganglib)
 * @license     http://www.gnu.org/licenses/lgpl.html
 */
 
/**
  * 
  * Abstract PDO Strategy class
  *
  * This class is a base for specific implementation of partitioning strategies.
  * All PDO-specific operations are implemented here. PDO is the fastest and
  * database-independent layer fot PHP.
  *  
  * @package    Div_Db_Distributor_Strategy_PDO
  * @copyright  Copyright (c) 2008 Ganglib project members (http://www.code.google.com/p/ganglib)
  * @license     http://www.gnu.org/licenses/lgpl.html 
  */ 
  require_once('Div/Db/Distributor/Strategy/Abstract.php');
abstract class Div_Db_Distributor_Strategy_PDO_Abstract extends Div_Db_Distributor_Strategy_Abstract
{
	/**
	 * PDO Object
	 *
	 * @var PDO
	 */
	protected $_connection;
	
	/**
	 * PDO Connection pool
	 *
	 * @var array
	 */
	protected $_connectionPool = array();
	
	/**
	 * Query distribution method.
	 * This is strategy specific.
	 *
	 * @param Div_Db_Query $query
	 * @return mixed
	 * @access public
	 */
	public function distributeQuery(Div_Db_Query $query)
	{
		return null;
	}
	
	/**
	 * Additional abstraction - runs query on specified connection/ If query is plain
	 * it could bind params etc.
	 * 
	 * @param PDO connection
	 * @param Div_Db_Query
	 * @return query result
	 */
	protected function runQuery($connection, Div_Db_Query $query)
	{
		if(!$query->isPlain())
			return $connection->query($query);
		else
		{
			$sql = $query->__toString();
			$params  = $query->plainParams();
			
			$stmt = $connection->prepare($sql);

			if($params)
			{
				foreach($params as $key => $val)
				{
					$stmt->bindParam($key, $val);
				}
			}
			return $stmt->execute();
		}		
	}
	
	/**
	 * Connect to database using schema from config
	 *
	 * @param strign $schema
	 * @return PDO
	 * @access public
	 */
	public function connect($schema)
	{	
		if(!isset($this->_schemas->{$schema}))
			self::throwException('No database schema: '.$schema.' defined in config');
		
		$schemas = $this->_schemas->{$schema}->toArray();
		if(!isset($this->_connectionPool[$schema]))
		{
			try
			{
				$this->_connectionPool[$schema] = new PDO($schemas['adapter'].':host='.$schemas['host'].';dbname='.$schemas['dbname'], $schemas['username'], $schemas['password']);
				$this->_connectionPool[$schema]->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
			}
			catch(Exception $e)
			{
				self::throwException($e);
			}
		}

		$this->_connection = $this->_connectionPool[$schema];
		
		if(isset($schemas['initQuery']))
		{
		    $this->_connection->query($schemas['initQuery']);
		}
		
		return $this->_connection;
	}
	
	
	/**
	 * Execute query
	 *
	 * @param Div_Db_Query $query
	 * @return mixed if query is insert - returns last insert ID;
	 * @access public
	 */
	public function execute(Div_Db_Query $query)
	{
		$result = $this->distributeQuery($query);
		$this->isCacheable = false;

		if($this->queryIsSelect($query))
		{
			if($result instanceof PDOStatement)
				$result = $result->fetchAll(PDO::FETCH_ASSOC);
				
			$this->isCacheable = true;
		} else 
		{
			if($result && $this->queryIsInsert($query))
			{
				$modelArray = $query->toModelArray();
				$result = $this->_connection->lastInsertId($modelArray['from'][0]);
			}
		}
			
		return $result;
	}	
	
	/**
	 * Checks if query is SELECT (since we don't want to cache updates etc.)
	 *
	 * @param Div_Db_Query $query
	 * @return bool
	 * @access public
	 */
	public function queryIsSelect(Div_Db_Query $query)
	{
		$modelArray = $query->toModelArray();
		return $modelArray['type'] == Div_Db_Query::QUERY_SELECT ? true : false;
	}
	
	/**
	 * Checks if query is INSERT - to return last insert ID
	 *
	 * @param Div_Db_Query $query
	 * @return bool
	 * @access public
	 */
	public function queryIsInsert(Div_Db_Query $query)
	{
		$modelArray = $query->toModelArray();
		return $modelArray['type'] == Div_Db_Query::QUERY_INSERT ? true : false;
	}	
}